#ifndef ASTNODE_H
#define ASTNODE_H

#include <vector>

#include "jtypes.h"
#include "MethodInfo.h"

//typedef std::vector<u4> RelocTable;


class RelocTable
{
  public:
    inline void push_back(u4 a) { table.push_back(a); }

    inline void reloc(MethodInfo * method,u4 target) {
      for(u4 i=0;i<table.size();i++) 
        method->relocAt(table[i],target);
    }

#if 0
    inline void absorbe(RelocTable & other) {
      for(u4 i=0;i<other.table.size();i++) 
        table.push_back(other.table[i]);
    }
#endif

    inline void clear() {
      table.clear();
    }

  private:
    std::vector<u4> table;
};

class ConstantPool;
class ClassFile;

class AstNodeExpression;

class AstNode 
{
   public:
     virtual void dump()=0;
     virtual int  compile(ClassFile * klass, MethodInfo * method)=0;
};

class AstNodeLiteral : public AstNode
{
   public:
     AstNodeLiteral(ConstantPool * cp, const char * text);
     virtual int  compile(ClassFile * klass, MethodInfo * method);

     virtual void dump();

   private:
     u4 string_index;
};

class AstNodePrint : public AstNode
{
  // pure virtual!! needed??
};

class AstNodePrintLiteral : public AstNodePrint
{
  public:
    AstNodePrintLiteral(AstNodeLiteral * son,bool endLine=true);
    virtual void dump();
    virtual int  compile(ClassFile * klass, MethodInfo * method);
  private:
    AstNodeLiteral * literal;
    bool             endLine;
};

class AstNodePrintExpression : public AstNodePrint
{
  public:
    AstNodePrintExpression(AstNodeExpression * son,bool endLine=true);
    virtual void dump();
    virtual int  compile(ClassFile * klass, MethodInfo * method);
  private:
    AstNodeExpression * expr;
    bool                endLine;
};


class AstNodeStatementList : public AstNode
{
  public:
    AstNodeStatementList();

    void         addNode(AstNode*);
    virtual int  compile(ClassFile * klass, MethodInfo * method);

    virtual void dump();
  private:
    std::vector<AstNode*> nodes;
};

class AstNodeExpression : public AstNode
{
  // pure virtual!!
};


class AstNodeExpressionVariable : public AstNodeExpression
{
  public:
    AstNodeExpressionVariable(u2 symbIndex);

    virtual void dump();
    virtual int  compile(ClassFile * klass, MethodInfo * method);
  private:
    u2 index;
};

class AstNodeDoubleConstant : public AstNodeExpression
{
  public:
     AstNodeDoubleConstant(ConstantPool*,double value);
     virtual void dump();
     virtual int  compile(ClassFile * klass, MethodInfo * method);
  private:
     u2 index;
};

class AstNodeBinaryOperator : public AstNodeExpression
{
  public:
    AstNodeBinaryOperator(int op, AstNodeExpression* left, AstNodeExpression *rite);
    virtual void dump();
    virtual int  compile(ClassFile * klass, MethodInfo * method);
  private:
    int op;
    AstNodeExpression * left;
    AstNodeExpression * rite;
};

class AstNodeLValue : public AstNode 
{
  public:
    AstNodeLValue(u2 symbIndex);
    virtual void dump();
    virtual int  compile(ClassFile * klass, MethodInfo * method);
  private:
    u2 index;
};

class AstNodeAssignment : public AstNode
{
  public:
    AstNodeAssignment(AstNode * lvalue, AstNodeExpression * expr);
    virtual int  compile(ClassFile * klass, MethodInfo * method);
    virtual void dump();

  private:
    AstNode *           lvalue;
    AstNodeExpression * expr;
};

class AstNodeCompareExpression : public AstNode
{
  public:
    enum {
      _equal,
      _less,
      _greater,
      _less_equal,
      _greater_equal,
      _not_equal
    };
    AstNodeCompareExpression(AstNodeExpression * left, AstNodeExpression  * expr, u1 cmpOperator);
    virtual int  compile(ClassFile * klass, MethodInfo * method);
    virtual void dump();

    u1 getOpcodeForFalse();
  private:
    AstNodeExpression * left;
    AstNodeExpression * rite;
    u1                  oper;
};



class AstNodeBooleanOperator : public AstNode
{
  public:
    enum {
      _and, _or, _not, _nop
    };
    AstNodeBooleanOperator(AstNodeBooleanOperator * left, AstNodeBooleanOperator  * expr, u1 cmpOperator);

    AstNodeBooleanOperator(AstNodeCompareExpression * cmp);

    virtual int  compile(ClassFile * klass, MethodInfo * method); 
    virtual void dump();

    int compileWithReloc(
        ClassFile * klass, MethodInfo * method,
        RelocTable & relocOnTrue,
        RelocTable & relocOnFalse);

  private:
    AstNodeBooleanOperator * left;
    AstNodeBooleanOperator * rite;
    u1                       oper;

    AstNodeCompareExpression * cmp;
};

class AstNodeIfStatement : public AstNode
{
  public:
    AstNodeIfStatement(
      AstNodeBooleanOperator * condition, 
      AstNodeStatementList  * true_body,
      AstNodeStatementList  * false_body);

    virtual int  compile(ClassFile * klass, MethodInfo * method);
    virtual void dump();
  private:
    AstNodeBooleanOperator * condition;
    AstNodeStatementList   * true_body;
    AstNodeStatementList   * false_body;
};

#endif
